//! @Author: DengLibin
//! @Date: Create in 2024-01-17 18:26:52
//! @Description: csp  接口 进行rsa加密和解密

#[cfg(windows)]
extern crate winapi;

use json::number::Number;
use json::object::Object;
use json::JsonValue;
use winapi::um::errhandlingapi::GetLastError;

use winapi::um::wincrypt::CryptAcquireContextA;

use winapi::um::wincrypt::CryptReleaseContext;

use winapi::um::wincrypt::HCRYPTPROV;

use winapi::shared::minwindef::BOOL;

use rust_common::base64;
use winapi::um::wincrypt::{CryptDestroyKey, PROV_RSA_FULL};
use winapi::{
    shared::winerror::{
        ERROR_BUSY, ERROR_NOT_ENOUGH_MEMORY, NTE_BAD_FLAGS, NTE_BAD_KEYSET, NTE_KEYSET_ENTRY_BAD,
        NTE_KEYSET_NOT_DEF, NTE_NO_MEMORY, NTE_PROV_DLL_NOT_FOUND,
    },
    um::wincrypt::{CryptDecrypt, CryptGetUserKey, AT_KEYEXCHANGE, HCRYPTKEY},
};

// CSP(加密服务提供商名称)
const PROVIDER_NAME: &str = "EnterSafe ePass3000GM CSP v1.0";

// usbkey中密钥容器名称
const CONTAINER: &str = "yiscn";

/// @Author: DengLibin
/// @Date: Create in 2024-01-18 11:12:43
/// @Description: 解密数据
#[cfg(windows)]
pub fn decrypyt(encrypt_base64: &str) -> String {
    //状态码 0:失败 1: 成功
    let code = 0;
    //信息
    let mut msg = String::new();

    let mut sz_provider = PROVIDER_NAME.as_bytes().to_vec();
    //加一个0结尾
    sz_provider.push(0);
    //转i8
    let provider_str = sz_provider
        .iter()
        .map(|item| *item as i8)
        .collect::<Vec<i8>>();
    //转指针
    let provider = provider_str.as_ptr();
    //清理
    drop(sz_provider);

    let mut sz_container = CONTAINER.as_bytes().to_vec();
    //加一个0结尾
    sz_container.push(0);
    //转i8
    let sz_container_str = sz_container
        .iter()
        .map(|item| *item as i8)
        .collect::<Vec<i8>>();
    //转指针
    let sz_container_p = sz_container_str.as_ptr();
    //清理
    drop(sz_container);

    unsafe {
        // 定义加密上下文句柄
        let mut hprov: HCRYPTPROV = 0;
        let hp = &mut hprov;
        //获取上下文句柄
        let b: BOOL = CryptAcquireContextA(hp, sz_container_p, provider, PROV_RSA_FULL, 0);

        let success: bool = b != 0;
        if !success {
            let error_code = GetLastError();
            if error_code as i32 == NTE_BAD_KEYSET {
                msg.push_str("无法打开密钥容器或容器不存在,请确认usb是否已插入");
            } else if error_code == ERROR_NOT_ENOUGH_MEMORY {
                msg.push_str("操作系统在操作期间内存不足");
            } else if error_code == ERROR_BUSY {
                msg.push_str("另一个线程或进程正在使用此密钥容器");
            } else if error_code as i32 == NTE_KEYSET_ENTRY_BAD {
                msg.push_str("找到 pszContainer 密钥容器，但已损坏");
            } else if error_code as i32 == NTE_KEYSET_NOT_DEF {
                msg.push_str("请求的提供程序不存在。");
            } else if error_code as i32 == NTE_NO_MEMORY {
                msg.push_str("CSP 在操作期间内存不足。");
            } else if error_code as i32 == NTE_PROV_DLL_NOT_FOUND {
                msg.push_str("提供程序 DLL 文件不存在或不在当前路径上。");
            } else if error_code as i32 == NTE_BAD_FLAGS {
                msg.push_str("dwFlags 参数的值无效。");
            }else{
                msg.push_str(format!("出错了,错误码:{0:#x}", error_code).as_str());

            }
        } else {
            //获取加密key
            let mut h_key: HCRYPTKEY = 0;

            if CryptGetUserKey(hprov, AT_KEYEXCHANGE, &mut h_key) == 0 {
                msg.push_str("获取加密key错误");
            } else {
                //使用外部加密的数据

                let mut content_v = base64::decode_to_bytes(encrypt_base64).unwrap();
                //反转
                let l = content_v.len();
                for i in 0..l / 2 {
                    let temp = content_v[i];
                    content_v[i] = content_v[l - 1 - i];
                    content_v[l - 1 - i] = temp;
                }
                let content_p = content_v.as_mut_ptr();
                let mut data_len = content_v.len() as u32;
                //解密数据
                if CryptDecrypt(h_key, 0, 1, 0, content_p, &mut data_len) == 0 {
                    msg.push_str("解密数据错误");
                } else {
                    let s = &content_v[0..data_len as usize];
                    let content = std::str::from_utf8(s).unwrap();
                    msg.push_str(content);
                }
            }

            let _ = CryptDestroyKey(h_key);
        }
        //释放
        let _ = CryptReleaseContext(hprov, 0);
        let s = json::stringify(Msg {
            code: code,
            msg: msg,
        });

        return s;
    }
}

struct Msg {
    code: i32,
    msg: String,
}

///实现Into<JsonValue>
impl Into<JsonValue> for Msg {
    fn into(self) -> JsonValue {
        let mut obj: Object = Object::new();

        obj.insert("code", JsonValue::Number(Number::from(self.code)));
        obj.insert("msg", JsonValue::String(self.msg));
        json::JsonValue::Object(obj)
    }
}
